#include "stdafx.h"
#include "BigInt.h"

using namespace System;
using namespace System::Text;
using namespace System::Collections::Generic;
using namespace Microsoft::VisualStudio::TestTools::UnitTesting;
using namespace APIAL;

namespace BigIntUnitTest
{
	[TestClass]
	public ref class ShiftUnitTest
	{
	private:
		TestContext^ testContextInstance;

	public: 
		/// <summary>
		///Gets or sets the test context which provides
		///information about and functionality for the current test run.
		///</summary>
		property Microsoft::VisualStudio::TestTools::UnitTesting::TestContext^ TestContext
		{
			Microsoft::VisualStudio::TestTools::UnitTesting::TestContext^ get()
			{
				return testContextInstance;
			}
			System::Void set(Microsoft::VisualStudio::TestTools::UnitTesting::TestContext^ value)
			{
				testContextInstance = value;
			}
		};

		#pragma region Additional test attributes
		//
		//You can use the following additional attributes as you write your tests:
		//
		//Use ClassInitialize to run code before running the first test in the class
		//[ClassInitialize()]
		//static void MyClassInitialize(TestContext^ testContext) {};
		//
		//Use ClassCleanup to run code after all tests in a class have run
		//[ClassCleanup()]
		//static void MyClassCleanup() {};
		//
		//Use TestInitialize to run code before running each test
		//[TestInitialize()]
		//void MyTestInitialize() {};
		//
		//Use TestCleanup to run code after each test has run
		//[TestCleanup()]
		//void MyTestCleanup() {};
		//
		#pragma endregion 

		[ClassInitialize]
		static void Initialize(Microsoft::VisualStudio::TestTools::UnitTesting::TestContext^ testContext) 
		{
			bi1 = new BigInt(4,8);
			bi2 = new BigInt(4,8);
			bi3 = new BigInt(4,8);
			bi4 = new BigInt(4,8);
			bi5 = new BigInt(4,8);
			bi6 = new BigInt(4,8);
			result = new BigInt(4,8);

			bi1->ParseBinaryString("11111111", true); // 8 1's
			bi2->ParseBinaryString("10101010", true);
			bi3->ParseBinaryString("100100100100100100100", true);
			bi4->ParseBinaryString("11111111111111111111111111111111", true); // 32 1's
			bi5->ParseBinaryString("0", true);
			bi6->ParseBinaryString("1", true);
		};

		[ClassCleanup]
		static void Cleanup() 
		{
			delete bi1;
			delete bi2;
			delete bi3;
			delete bi4;
			delete bi5;
			delete bi6;
			delete result;
		};

#pragma region LeftShift Unit Tests

		[TestMethod]
		void TestLeftShiftMethod1()
		{
			LeftShift(bi1, 8, result);
			Assert::AreEqual<String^>("1111111100000000", gcnew String((PrintMagnitudeBinary(result)).c_str()));
		}

		[TestMethod]
		void TestLeftShiftMethod3()
		{
			LeftShift(bi3, 8, result);
			Assert::AreEqual<String^>("10010010010010010010000000000", gcnew String((PrintMagnitudeBinary(result)).c_str()));
		};

		[TestMethod]
		void TestLeftShiftMethod4()
		{
			LeftShift(bi4, 64, result);
			Assert::AreEqual<String^>("111111111111111111111111111111110000000000000000000000000000000000000000000000000000000000000000", gcnew String((PrintMagnitudeBinary(result)).c_str()));
		};

		[TestMethod]
		void TestLeftShiftMethod5()
		{
			LeftShift(bi5, 8, result);
			Assert::AreEqual<String^>("0", gcnew String((PrintMagnitudeBinary(result)).c_str()));
		};

		[TestMethod]
		void TestLeftShiftMethod6()
		{
			LeftShift(bi4, 0, result);
			Assert::AreEqual<String^>("11111111111111111111111111111111", gcnew String((PrintMagnitudeBinary(result)).c_str()));
		};

#pragma endregion

#pragma region RightShift Unit Tests

		[TestMethod]
		void TestRightShiftMethod1()
		{
			RightShift(bi1, 4, result);
			Assert::AreEqual<String^>("1111", gcnew String((PrintMagnitudeBinary(result)).c_str()));
		};

		[TestMethod]
		void TestRightShiftMethod2()
		{
			RightShift(bi2, 6, result);
			Assert::AreEqual<String^>("10", gcnew String((PrintMagnitudeBinary(result)).c_str()));
		};

		[TestMethod]
		void TestRightShiftMethod3()
		{
			RightShift(bi3, 8, result);
			Assert::AreEqual<String^>("1001001001001", gcnew String((PrintMagnitudeBinary(result)).c_str()));
		};

		[TestMethod]
		void TestRightShiftMethod4()
		{
			RightShift(bi4, 13, result);
			Assert::AreEqual<String^>("1111111111111111111", gcnew String((PrintMagnitudeBinary(result)).c_str()));
		};

		[TestMethod]
		void TestRightShiftMethod5()
		{
			RightShift(bi5, 8, result);
			Assert::AreEqual<String^>("0", gcnew String((PrintMagnitudeBinary(result)).c_str()));
		};

		[TestMethod]
		void TestRightShiftMethod6()
		{
			RightShift(bi6, 400, result);
			Assert::AreEqual<String^>("0", gcnew String((PrintMagnitudeBinary(result)).c_str()));
		};

		[TestMethod]
		void TestRightShiftMethod7()
		{
			RightShift(bi4, 0, result);
			Assert::AreEqual<String^>("11111111111111111111111111111111", gcnew String((PrintMagnitudeBinary(result)).c_str()));
		}

#pragma endregion

#pragma region Combined Shift Unit Tests

		[TestMethod]
		void TestCombineShiftMethod1()
		{
			LeftShift(bi1, 1280, result);
			Assert::AreEqual<String^>("1111111100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", gcnew String((PrintMagnitudeBinary(result)).c_str()));
			RightShift(result, 1280, result);
			Assert::AreEqual<String^>("11111111", gcnew String((PrintMagnitudeBinary(result)).c_str()));
		}

		[TestMethod]
		void TestCombineShiftMethod2()
		{
			RightShift(bi2, 1280, result);
			Assert::AreEqual<String^>("0", gcnew String((PrintMagnitudeBinary(result)).c_str()));
			LeftShift(result, 1280, result);
			Assert::AreEqual<String^>("0", gcnew String((PrintMagnitudeBinary(result)).c_str()));
		}

		[TestMethod]
		void TestCombineShiftMethod3()
		{
			LeftShift(bi6, 1280, result);

			for (int i = 0; i < 100; i++)
			{
				int random = rand() % 10000;
				LeftShift(result, random, result);
				RightShift(result, random, result);
			}

			RightShift(result, 1280, result);

			Assert::AreEqual<String^>("1", gcnew String((PrintMagnitudeBinary(result)).c_str()));
		}

#pragma endregion

	private:
		static BigInt* bi1;
		static BigInt* bi2;
		static BigInt* bi3;
		static BigInt* bi4;
		static BigInt* bi5;
		static BigInt* bi6;
		static BigInt* result;
	};
}
